package cn.zhl.algorithm._4_图.impl;

import cn.zhl.algorithm._4_图.Graph;

import java.util.*;

/**
 * @program: demos
 * @description:
 * @author: 刘振华
 * @create: 2020-06-15 17:36
 **/
public class SetGraph<V,E> implements Graph<V,E> {
	private Set<Edge<V,E>> edgeSet = new HashSet<>();
	private Map<V,Vertex<V,E>> vertexMap = new HashMap<>();
	@Override
	public int vertexSize() {
		return vertexMap.size();
	}

	@Override
	public int edgeSize() {
		return edgeSet.size();
	}

	@Override
	public void addVertex(V v) {
		if(!vertexMap.containsKey(v)) {
			Vertex<V, E> vertex = new Vertex<>(v);
			vertexMap.put(v,vertex);
		}
	}

	@Override
	public void addEdge(V from, V to) {
		addEdge(from,to,null);
	}

	@Override
	public void addEdge(V from, V to, E weight) {
		Edge<V,E> edge = new Edge<>(from, to,weight);
		Vertex<V, E> fromVertex = new Vertex<>(from);
		Vertex<V, E> toVertex = new Vertex<>(to);
		if(fromVertex.out.remove(edge)){
			toVertex.in.remove(edge);
		}
		fromVertex.out.add(edge);
		toVertex.in.add(edge);
		edgeSet.add(edge);
	}

	@Override
	public void deleteVertex(V v) {
		Vertex<V, E> vertex =vertexMap.remove(v);
		vertex.in.forEach(edge-> {
			vertexMap.get(edge.from).out.remove(edge);
			edgeSet.remove(edge);
		});
		vertex.out.forEach(edge-> {
			vertexMap.get(edge.to).in.remove(edge);
			edgeSet.remove(edge);
		});
	}

	@Override
	public void deleteEdge(V from, V to) {
		Edge<V,E> edge = new Edge<>(from,to);
		Vertex<V, E> fromVertex = new Vertex<>(from);
		Vertex<V, E> toVertex = new Vertex<>(to);
		edgeSet.remove(edge);
		fromVertex.out.remove(edge);
		toVertex.in.remove(edge);
	}

	private static class Vertex<V,E>{
		V value;
		Set<Edge<V,E>> in = new HashSet<>();
		Set<Edge<V,E>> out = new HashSet<>();
		public Vertex(V v){
			this.value = v;
		}

		@Override
		public boolean equals(Object o) {
			if (this == o) {
				return true;
			}
			if (!(o instanceof Vertex)) {
				return false;
			}
			Vertex<V,E> vertex = (Vertex<V,E>) o;
			return Objects.equals(value, vertex.value);
		}

		@Override
		public int hashCode() {
			return Objects.hash(value);
		}
	}
	private static class Edge<V,E>{
		V from;
		V to;
		E weight;
		@Override
		public boolean equals(Object o) {
			if (this == o) {
				return true;
			}
			if (!(o instanceof Edge)) {
				return false;
			}
			Edge<V,E> edge = (Edge<V,E>) o;
			return Objects.equals(from, edge.from) &&
				Objects.equals(to, edge.to);
		}

		@Override
		public int hashCode() {
			return Objects.hash(from, to);
		}
		public Edge(V from,V to,E weight){
			this.from = from;
			this.to = to;
			this.weight = weight;
		}
		public Edge(V from,V to){
			this(from,to,null);
		}
	}
}
